CanIf模块在AUTOSAR架构中位于底层CAN驱动(CanDrv)与上层通信服务模块(如PduR、CanNm、CanTp等)之间实际上就是在Can驱动的基础上再次封装了一层,供上层统一使用,如下图所示:
其主要功能包括:
实现Pdu数据的收发,为上层模块与底层驱动间通信提供对应的收发接口;
实现CAN控制器模式的控制,通过上层模块下发模式切换请求对应修改控制器模式;
实现Pdu模式控制,通过上层模块下发通道模式切换请求对应修改Pdu模式。
关于Pdu详细概念,建议跳转查看:
AUTOSAR 通信栈中的 PDU:L-PDU、N-PDU、I-PDU及数据流
在介绍CanIf相关功能前,我们首先来理解几个概念:Hardware Object Handles(HOH)、Hardware Transmit Handles(HTH)和Hardware Receive Handles(HRH)。
HOH:是CAN中邮箱的数据结构抽象,它包括CanId、DataLength(数据长度)和数据等CAN帧相关信息。
HRH:是HOH中的一种,用于引用一个CAN控制器邮箱的接收Handle(句柄)。一个HRH可以通过配置为FullCan类型用于接收一个特定的CanId或者配置为BasicCan类型用于接收范围内的一组CanId。
HTH:是HOH中的一种,用于引用一个CAN控制器邮箱的发送Handle(句柄)。
Full CAN:一个HOH只能接收或者发送一个CAN报文(或者说一个L-PDU),HOH可以配置成HTH或者HRH。
Basic CAN:一个HOH接收或者发送多个CAN 报文(或者说多个L-PDU),HOH可以配置成HTH或者HRH。
HOH实质就是存放收/发CAN报文信息的RAM区,该区域可以按需所取,也就是说:根据项目的情况(收/发的CAN报文数目),配置Message RAM使用的空间,实际工程,建议全部使用。Message RAM就好比一块蛋糕,总大小是一定的,你能吃多少,就切多少。
下图体现了CanIf与硬件对象句柄的映射路径:
如果在CAN总线中接收到符合配置的CAN帧,CanDrv通过调用CanIf的CanIf_RxIndication ()接口,将接收到CAN报文数据组装成Pdu数据向上层模块传递并在上层模块中进行评估和处理,上层模块不能直接操作或访问CanDrv的缓冲区。
HRH标识CAN硬件接收句柄,接收CAN帧。在CanDrv中调用CanIf_RxIndication(),指示接收到CAN帧后,CanIf将依据接收CAN帧的HRH配置(FullCan或BasicCan)匹配到对应的Pdu,根据配置进行不同处理。
FullCan:HRH接收到的为特定的CAN帧,CanDrv中调用CanIf_RxIndication()时得到标准的Pdu,该Pdu将在CanIf中依据配置的CanId进行判断是否为FullCan。为FullCan则进行数据长度检查,检查当前接收Pdu是否是一个完整的CAN数据帧。校验通过后CanIf通过CanIfRxPduUserRxIndicationUL,CanIfRxPduUserRxIndicationName两个配置参数识别是否配置了目标上层模块,若配置上层模块将该Pdu数据传递至指定模块中。在传递过程中CAN硬件接收句柄序号会被锁定,直到复制到上层模块缓冲区中结束后立即释放。
BasicCan:HRH依据配置的CanId范围(硬件过滤)接收到的CAN帧,CanDrv中调用CanIf_RxIndication()时得到标准的Pdu,该Pdu将在CanIf中依据配置的CanId范围进行判断是否为需要接收的Pdu(软件过滤)。若为需要接收Pdu则进行数据长度检查,检查当前接收Pdu是否是一个完整的CAN数据帧。校验通过后CanIf通过CanIfRxPduUserRxIndicationUL、CanIfRxPduUserRxIndicationName两个配置参数识别是否配置了目标上层模块,若配置上层模块将该Pdu数据传递至指定模块中。在传递过程中CAN硬件接收句柄序号会被锁定,直到复制到上层模块缓冲区中结束后立即释放。
CanIf的数据接收流程如下所示:
再来看一下Pdu接收的函数接口调用流程,这里还是以中断模式为例:
当CanController接收到数据触发接收中断后,先判断是否需用临时缓冲区进行数据规范化并做相应处理,接着CanIf模块通过CanIf_RxIndication函数接收数据,进行软件过滤、L - PDU分配等操作,再经User_RxIndication函数指示给用户层,期间依情况进行数据复制,最后CanController验证硬件对象并准备接收下次中断。
CanIf的发送请求函数CanIf_Transmit()是上层模块请求发送Pdu的通用接口。如果CanDrv能够将PDU数据写入CAN硬件传输对象中,则发起的传输请求成功完成。上层模块通过调用CanIf_Transmit ()来发起一个发送请求。
CanIf_Transmit()对PDU发送前执行以下操作:
检查CanIf的发送状态(控制器模式、Pdu通信模式)
当使用多个CanDrv时,匹配对应的CanDrv
根据配置找到对应的CAN硬件传输对象HTH
调用CanDrv的Can_Write()
在CanIf收到上层模块的发送请求后,函数CanIf_Transmit()通过PduId找到对应的HTH邮箱,并调用函数Can_Write()。
若发送成功,CanDrv将调用CanIf_TxConfirmation()通知CanIf模块,当前发送数据成功发送可以发送下一个Pdu数据。CanIf将接收到的通知通过配置中的<User TxConfirmation>(User:上层模块)参数,通知到上层模块可继续请求发送下一个Pdu数据。
若发送失败,且Pdu未配置发送缓冲,则CanIf_Transmit()将返回E_NOT_OK;若启用了发送缓冲,将本次发送的Pdu数据存储在缓冲区CanIfTxBuffer中,CanIf_Transmit()也会返回E_OK值,CanIf通过CanIf_TxConfirmation()回调处理未完成的发送,使上层无需重新提出传输请求,在CanIf_TxConfirmation()中再次处理发送后,若仍未成功,将依据CanIf中相关处理方式(如丢弃或插入缓冲中待HTH空闲时重新发送等)进行不同操作。
CanIf的数据发送流程如下所示:
传输过程的函数调用关系如下图:
发送完成后,底层驱动会调用上层通知函数通知上层发送完成,以便上层进一步处理,整个流程如下图所示:
在CanIf中无论是接收还是发送,都需要对控制器模式进行控制,控制器共有如下四种状态:
CANIF_CS_UNINIT:控制器未初始化,需将控制初始化后进行后续操作
CANIF_CS_STOPPED :控制器处于停止状态,接收和发送操作无法进行
CANIF_CS_STARTED:控制器处于启动状态,可以进行接收和发送操作
CANIF_CS_SLEEP: 控制器处于睡眠状态,在唤醒前无法接收和发送操作,唤醒后可以继续进行接收和发送操作
在初始完成后,控制器模式处于STOPPED状态,无法进行接收和发送操作。但上层模块可通过调CanIf_SetControllerMode()接口请求更改CAN控制器状态。上层模的请求通过CanIf经过CanDrv的特定API传递到指定的CAN控制器。CanIf通过调用函数CanIf_SetControllerMode()或CanIf_ControllerBusOff()接受每个状态转换请求。CanIf不决定CAN控制器请求的模式转换是否有效。CanIf仅通过获取当前模式和执行请求的模式转换来与CanDrv交互确定当前控制器状态,仅提供一个桥梁的工作。
CanIf设置控制模式如下图所示:
在CanIf中Pdu的接收和发送除受控制器模式影响外,还受Pdu通信模式控制,只有当控制模式处于CANIF_CS_STARTED时才允许更改Pdu通道模式,不同模式下Pdu的通信能力如下:
CANIF_OFFLINE:关闭Pdu通道,不允许进行Pdu的接收与发送操作
CANIF_ONLINE:开启Pdu通道,允许进行Pdu的接收与发送操作
CANIF_TX_OFFLINE:开启发送Pdu通道关闭Pdu接收通道,允许进行Pdu的发送但不允许接收Pdu
CANIF_TX_OFFLINE_ACTIVE:模拟成功传输
在初始化期间,CanIf应该将每个通道切换到CANIF_OFFLINE。CanIf通过调用CanIf_GetPduMode()提供关于当前Pdu通道模式的信息
对于切换到CANIF_OFFLINE模式的物理通道,CanIf应该:
防止将相关L-PDU的传输请求CanIf_Transmit()转发给CanDrv。
清除相应的CanIf传输缓冲区。
防止调用上层模块的接收通知回调服务。
防止调用上层模块的传输确认回调服务。
如果底层调用CanIf_SetControllerMode()或CanIf_ControllerBusOff(),则CanIf应将相应通道的PDU通道模式设置为CANIF_TX_OFFLINE。
对于切换到CANIF_ONLINE模式的物理信道,CanIf应该:
允许将相关L-PDU的传输请求CanIf_Transmit()转发到CanDrv。
支持调用上层模块的接收指示回调服务。
允许调用上层模块的传输确认回调服务。
如果CanIfTxOfflineActiveSupport为TRUE,CanIf提供通过CANIF_TX_OFFLINE_ACTIVE模式来模拟成功传输。对于每个被分配到CANIF_TX_OFFLINE_ACTIVE模式信道的pdu CanIf会立即调用上层模块的传输确认回调服务,而不是在调用CanIf_Transmit()时将Pdu缓冲或转发到CanDrv。
Pdu通道模式转化如下图所示:
本章节的配置项截图均来自EasySAR网页端的配置工具
该容器主要配置CanIf控制的控制器相关信息。
该容器主要配置分配任务相关信息。
该容器主要配置CanIf初始化时相关参数
该同期主要配置CanIf缓冲区相关参数
该容器主要配置CanIfHoh中Hrh相关参数
该容器主要配置Hrh中接收范围相关参数
该容器主要配置CanIfHoh中Hth相关参数
该容器主要配置接收Pdu的相关参数
该容器主要配置发送Pdu的相关参数
该容器主要配置私有接口相关参数
该容器主要配置公共接口相关参数